package com.stud.common.utils;

import java.util.Arrays;

/**
 * 基于Modbus CRC16的校验算法工具类
 */
public class Crc16Util {
    private static final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public static String bytes2Hex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX[v >>> 4];
            hexChars[j * 2 + 1] = HEX[v & 0x0F];
        }
        return new String(hexChars);
    }

    /**
     * CRC验证码装换
     */
    public static String getHj212Crc16(byte[] bytes) {
        int crcRegister = 0xFFFF;
        for (byte aByte : bytes) {
            crcRegister = (crcRegister >> 8) ^ aByte;
            for (int j = 0; j < 8; j++) {
                int check = crcRegister & 0x0001;
                crcRegister >>= 1;
                if (check == 0x0001) {
                    crcRegister ^= 0xA001;
                }
            }
        }
        //转十六进制
        return String.format("%04x", crcRegister);
    }

    /**
     * 获取验证码byte数组，基于Modbus CRC16的校验算法
     */
    public static byte[] getCrc16(byte[] bytes) {
        int crc = 0xFFFF;
        for (byte data : bytes) {
            crc = crc ^ (data & 0XFF);
            for (int i = 0; i < 8; i++) {
                crc = (crc & 0X0001) == 1 ? (crc >> 1) ^ 0XA001 : crc >> 1;
            }
        }
        return int2Bytes(crc);
    }

    /**
     * 将int转换成byte数组，低位在前，高位在后 改变高低位顺序只需调换数组序号
     */
    public static byte[] int2Bytes(int value) {
        short num = (short) value;
        byte[] src = new byte[2];
        src[1] = (byte) ((num >> 8) & 0xFF);
        src[0] = (byte) (num & 0xFF);
        return src;
    }

    public static int bytes2Int(byte[] bytes) {
        int res = 0;
        for (int i = 0; i < bytes.length; i++) {
            res += (bytes[i] & 0xff) << i * 8;
        }
        return res;
    }

    public static int bytes2Int(byte byte0, byte byte1) {
        return (short) ((byte1 & 0xff) | (byte0 & 0xff) << 8);
    }

    public static int bytes2Int(byte byte0, byte byte1, byte byte2, byte byte3) {
        return (byte3 & 0xff) | (byte2 & 0xff << 8) | (byte1 & 0xff << 16) | (byte0 & 0xff) << 24;
    }

    public static byte[] escape(byte[] bytes) {
        int len = bytes.length;
        byte[] result = new byte[len];
        boolean flag = false;
        int index = 0;
        for (int i = 0; i < bytes.length; i++) {
            result[index] = bytes[i];
            if (bytes[i] == 0x54) {
                flag = true;
            } else if (flag) {
                flag = false;
                if (bytes[i] == 0x01) {
                    result[--index] = 0x55;
                } else if (bytes[i] == 0x02) {
                    index--;
                }
            }
            index++;
        }
        return Arrays.copyOfRange(result, 0, index);
    }
}
